mod init_project_api_json;
mod merge_api_json;
mod resolve_path;
mod run_command;
mod run_gen_api;
mod capitalize_first_letter;
pub mod vue3;

use super::traits::{ImportDeclTrait, KeyValuePropTrait, ObjectLitTrait};
use crate::model::LibImport;
use std::rc::Rc;
use swc_common::Span;
use swc_common::{
    source_map::{FilePathMapping, SourceMap},
    FileName,
};
use swc_ecma_ast::*;
use swc_ecma_parser::{parse_file_as_module, EsSyntax, Syntax};

pub use init_project_api_json::init_project_api_json;
pub use merge_api_json::merge_api_json;
pub use resolve_path::resolve_path;
pub use run_command::run_command;
pub use run_gen_api::run_gen_api;
pub use capitalize_first_letter::capitalize_first_letter;

pub fn print_err<E: std::fmt::Debug>(e: &E) -> ! {
    eprintln!("{:?}", e);
    std::process::exit(1);
}

pub fn create_ast(source_code: &str) -> Module {
    let cm = SourceMap::new(FilePathMapping::empty());
    let fm = cm.new_source_file(
        Rc::new(FileName::Custom("test.ts".into())),
        source_code.to_string(),
    );
    parse_file_as_module(
        &fm,
        Syntax::Es(EsSyntax::default()),
        EsVersion::Es2024,
        None,
        &mut vec![],
    )
    .map_err(|e| format!("{:?}", e))
    .expect("create_ast error")
}

// 解析vite.config.ts文件为AST
pub fn parse_vite_config_ts(ts_source_code: &str) -> Result<Module, Box<dyn std::error::Error>> {
    let cm = SourceMap::new(FilePathMapping::empty());
    let fm = cm.new_source_file(
        Rc::new(FileName::Custom("none".to_string())),
        ts_source_code.to_string(),
    );
    let module = parse_file_as_module(
        &fm,
        Syntax::Es(EsSyntax::default()),
        EsVersion::Es2024,
        None,
        &mut vec![],
    )
    .map_err(|e| format!("{:?}", e))?;
    Ok(module)
}

pub fn write_content_at(
    origin_content: &str,
    pos: usize,
    content: &str,
) -> Result<String, std::io::Error> {
    // 检查位置是否有效
    if pos > origin_content.len() {
        // 如果位置超过字符串长度，返回错误
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            "Position exceeds the length of the original content",
        ));
    }

    let new_content = origin_content[..pos].to_owned() + content + &origin_content[pos..];
    Ok(new_content)
}

impl KeyValuePropTrait for KeyValueProp {
    fn get_key_name(&self) -> String {
        match &self.key {
            PropName::Ident(IdentName { sym, .. }) => format!("{}", sym),
            PropName::Str(Str { value, .. }) => format!("{}", value),
            _ => "not_supported_name".to_string(),
        }
    }
    fn get_value_as_object_lit(&self) -> Option<ObjectLit> {
        if let Expr::Object(object_lit) = (*self.value).clone() {
            return Some(object_lit);
        }
        None
    }
    fn get_value_span(&self) -> Result<Span, std::io::Error> {
        let value_span = match *self.value {
            Expr::Object(ObjectLit { span, .. }) => span,
            _ => {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::InvalidData,
                    format!("get_value_span: 无效的值定义:{:?}", self.value),
                ))
            }
        };
        Ok(value_span)
    }
}

impl ObjectLitTrait for ObjectLit {
    fn try_get_object_value(&self, prop_key: &str) -> Option<ObjectLit> {
        for prop in &self.props {
            if let PropOrSpread::Prop(prop_box) = prop {
                if let Prop::KeyValue(KeyValueProp { key, value }) = &**prop_box {
                    if let PropName::Str(Str { value: key_str, .. }) = key {
                        if key_str == prop_key {
                            if let Expr::Object(_value) = &**value {
                                return Some(_value.clone());
                            }
                            break;
                        }
                    }
                    if let PropName::Ident(IdentName { sym, .. }) = key {
                        if format!("{}", sym) == prop_key {
                            if let Expr::Object(_value) = &**value {
                                return Some(_value.clone());
                            }
                            break;
                        }
                    }
                }
            }
        }

        None
    }
    fn has_key(&self, prop_key: &str) -> bool {
        for prop in &self.props {
            if let PropOrSpread::Prop(prop_box) = prop {
                if let Prop::KeyValue(KeyValueProp { key, .. }) = &**prop_box {
                    if let PropName::Str(Str { value: key_str, .. }) = key {
                        if key_str == prop_key {
                            return true;
                        }
                    }
                    if let PropName::Ident(IdentName { sym, .. }) = key {
                        if format!("{}", sym) == prop_key {
                            return true;
                        }
                    }
                }
            }
        }

        false
    }
}

impl ImportDeclTrait for ImportDecl {
    fn has_element(&self, import_def: &LibImport) -> bool {
        // 检查库名称是否匹配
        if self.src.value != import_def.lib_name {
            return false;
        }

        // 遍历specifiers，检查是否包含指定的导入元素
        for specifier in &self.specifiers {
            match specifier {
                ImportSpecifier::Named(named) => {
                    if !import_def.is_default && named.local.sym == import_def.element_name {
                        return true;
                    }
                }
                ImportSpecifier::Default(default) => {
                    if import_def.is_default && default.local.sym == import_def.element_name {
                        return true;
                    }
                }
                ImportSpecifier::Namespace(namespace) => {
                    if namespace.local.sym == import_def.element_name {
                        return true;
                    }
                }
            }
        }

        false
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::traits::ObjectLitTrait;
    use swc_common::DUMMY_SP;
    use swc_ecma_ast::{Expr, KeyValueProp, Lit, ObjectLit, Prop, PropName, PropOrSpread, Str};

    #[test]
    fn test_try_get_object_value() {
        // 构造 ObjectLit 节点
        let obj_value = ObjectLit {
            span: DUMMY_SP,
            props: vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
                key: PropName::Str(Str {
                    span: DUMMY_SP,
                    value: "key2_1".into(),
                    raw: None,
                }),
                value: Box::new(Expr::Lit(Lit::Str(Str {
                    span: DUMMY_SP,
                    value: "value2_2".into(),
                    raw: None,
                }))),
            })))],
        };

        let obj = ObjectLit {
            span: DUMMY_SP,
            props: vec![
                PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
                    key: PropName::Str(Str {
                        span: DUMMY_SP,
                        value: "key1".into(),
                        raw: None,
                    }),
                    value: Box::new(Expr::Lit(Lit::Str(Str {
                        span: DUMMY_SP,
                        value: "value1".into(),
                        raw: None,
                    }))),
                }))),
                PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
                    key: PropName::Str(Str {
                        span: DUMMY_SP,
                        value: "key2".into(),
                        raw: None,
                    }),
                    value: Box::new(Expr::Object(obj_value.clone())),
                }))),
            ],
        };

        // 测试存在的键
        assert_eq!(obj.try_get_object_value("key1"), None);
        assert_eq!(obj.try_get_object_value("key2"), Some(obj_value));

        // 测试不存在的键
        assert_eq!(obj.try_get_object_value("key3"), None);
    }

    // write_content_at test
    #[test]
    fn test_write_content_at_middle() -> Result<(), std::io::Error> {
        let result = write_content_at("Hello", 2, "abc");
        assert_eq!(result?, "Heabcllo");
        Ok(())
    }

    #[test]
    fn test_write_content_at_start() -> Result<(), std::io::Error> {
        let result = write_content_at("World", 0, "Hello ");
        assert_eq!(result?, "Hello World");
        Ok(())
    }

    #[test]
    fn test_write_content_at_end() -> Result<(), std::io::Error> {
        let result = write_content_at("Hello", 5, " World");
        assert_eq!(result?, "Hello World");
        Ok(())
    }

    #[test]
    fn test_write_content_at_invalid_position() -> Result<(), std::io::Error> {
        let result = write_content_at("Hello", 10, " World");
        assert!(result.is_err());
        Ok(())
    }
}
